package main

import (
	"fmt"
	goredislib "github.com/go-redis/redis/v8"
	"github.com/go-redsync/redsync/v4"
	"github.com/go-redsync/redsync/v4/redis/goredis/v8"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"gorm.io/gorm/schema"
	"log"
	"os"
	"sync"
	"time"
)

var DB *gorm.DB

type BaseModel struct {
	ID        int32          `gorm:"primary_key;comment:ID" json:"id"`
	CreatedAt time.Time      `gorm:"column:add_time;comment:创建时间" json:"-"`
	UpdatedAt time.Time      `gorm:"column:update_time;comment:更新时间" json:"-"`
	DeletedAt gorm.DeletedAt `gorm:"comment:删除时间" json:"-"`
	IsDeleted bool           `gorm:"comment:是否删除" json:"-"`
}

type Inventory struct {
	BaseModel
	Goods   int32 `gorm:"type:int;index;comment:商品id"`
	Stocks  int32 `gorm:"type:int;comment:仓库"`
	Version int32 `gorm:"type:int;comment:分布式锁-乐观锁"`
}

func InitDB() {

	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8mb4&parseTime=True&loc=Local",
		"root", "123456", "localhost", 3306, "mxshop_inventory_srv2")
	newLogger := logger.New(
		log.New(os.Stdout, "\r\n", log.LstdFlags), // io writer（日志输出的目标，前缀和日志包含的内容——译者注）
		logger.Config{
			SlowThreshold: time.Second, // 慢 SQL 阈值
			LogLevel:      logger.Info, // 日志级别
			//LogLevel: logger.Silent, // 日志级别
			//IgnoreRecordNotFoundError: true,        // 忽略ErrRecordNotFound（记录未找到）错误
			Colorful: true, // 禁用彩色打印
		},
	)
	// 参考 https://github.com/go-sql-driver/mysql#dsn-data-source-name 获取详情
	var err error
	DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{
		NamingStrategy: schema.NamingStrategy{
			SingularTable: true,
		},
		Logger: newLogger,
	})
	if err != nil {
		panic(err)
	}
}
func main() {
	InitDB()
	client := goredislib.NewClient(&goredislib.Options{
		Addr: "121.40.213.174:6301",
	})
	pool := goredis.NewPool(client)
	rs := redsync.New(pool)
	gNum := 20
	var wg sync.WaitGroup
	wg.Add(gNum)
	DB.Transaction(func(tx *gorm.DB) error {
		for i := 0; i < gNum; i++ {
			go func() {
				defer wg.Done()
				var inv Inventory
				mutex := rs.NewMutex(fmt.Sprintf("goodsss_%d", 421))
				if err := mutex.Lock(); err != nil {
					fmt.Println("获取redis分布式锁异常-1")
				}
				if result := DB.Where(&Inventory{Goods: int32(421)}).First(&inv); result.RowsAffected == 0 {
					panic("库存信息不存在")
				}
				fmt.Println(inv.Stocks)
				if err := tx.Model(&Inventory{}).Select("Stocks").Where("goods = ?", int32(421)).Update("stocks", inv.Stocks-1); err.RowsAffected == 0 {
					fmt.Println("更新失败：", err.Error.Error())
					fmt.Println(inv.Stocks)
				}
				if ok, err := mutex.Unlock(); !ok || err != nil {
					fmt.Println("释放redis分布式锁异常-4")
				}
			}()
		}
		return nil
	})
	wg.Wait()
}
